<template>
  <div
    ref="draggableRef"
    :class="['draggable', { 'is-dragging': isDragging }]"
    :style="computedStyle"
    @mousedown="handleMouseDown"
    @touchstart="handleTouchStart"
  >
    <slot></slot>
  </div>
</template>

<script>
import { ref, computed, onMounted, onUnmounted } from 'vue'

export default {
  name: 'Draggable',
  props: {
    x: {
      type: Number,
      default: 0
    },
    y: {
      type: Number,
      default: 0
    },
    disabled: {
      type: Boolean,
      default: false
    },
    bounds: {
      type: [String, Object],
      default: 'parent'
    },
    handle: {
      type: String,
      default: null
    }
  },
  emits: ['update:x', 'update:y', 'drag-start', 'drag-move', 'drag-end'],
  setup(props, { emit }) {
    const draggableRef = ref(null)
    const isDragging = ref(false)
    const startX = ref(0)
    const startY = ref(0)
    const elementX = ref(props.x)
    const elementY = ref(props.y)
    const initialElementX = ref(props.x)
    const initialElementY = ref(props.y)
    const bounds = ref(null)

    // 计算样式 - 使用缓存优化性能
    const computedStyle = computed(() => {
      const x = elementX.value
      const y = elementY.value
      const dragging = isDragging.value
      const disabled = props.disabled
      
      return {
        position: 'absolute',
        left: x + 'px',
        top: y + 'px',
        cursor: disabled ? 'default' : (dragging ? 'grabbing' : 'grab'),
        userSelect: 'none',
        zIndex: dragging ? 9999 : 'auto',
        transition: dragging ? 'none' : 'all 0.2s cubic-bezier(0.4, 0, 0.2, 1)',
        willChange: dragging ? 'transform' : 'auto',
        touchAction: 'none'
      }
    })

    // 计算边界 - 使用缓存优化性能
    let boundsCache = null
    let cacheTimestamp = 0
    const CACHE_DURATION = 100 // 缓存100ms
    
    const calculateBounds = () => {
      if (!draggableRef.value) return null
      
      // 使用缓存避免频繁的DOM查询
      const now = Date.now()
      if (boundsCache && now - cacheTimestamp < CACHE_DURATION) {
        return boundsCache
      }

      if (props.bounds === 'parent') {
        const parent = draggableRef.value.parentElement
        if (!parent) return null

        // 获取父容器的实际尺寸（包括padding和border）
        const parentWidth = parent.clientWidth || parent.offsetWidth
        const parentHeight = parent.clientHeight || parent.offsetHeight
        
        // 获取拖拽元素的实际尺寸
        const elementWidth = draggableRef.value.offsetWidth
        const elementHeight = draggableRef.value.offsetHeight
        
        // 计算边界，确保元素完全在容器内
        boundsCache = {
          top: 0,
          right: Math.max(0, parentWidth - elementWidth),
          bottom: Math.max(0, parentHeight - elementHeight),
          left: 0
        }
        cacheTimestamp = now
        return boundsCache
      }

      if (typeof props.bounds === 'object') {
        boundsCache = props.bounds
        cacheTimestamp = now
        return boundsCache
      }

      return null
    }

    // 限制位置在边界内
    const constrainPosition = (x, y) => {
      if (!bounds.value) return { x, y }

      let newX = x
      let newY = y

      if (bounds.value.left !== undefined) {
        newX = Math.max(bounds.value.left, newX)
      }
      if (bounds.value.right !== undefined) {
        newX = Math.min(bounds.value.right, newX)
      }
      if (bounds.value.top !== undefined) {
        newY = Math.max(bounds.value.top, newY)
      }
      if (bounds.value.bottom !== undefined) {
        newY = Math.min(bounds.value.bottom, newY)
      }

      return { x: newX, y: newY }
    }

    // 鼠标按下事件
    const handleMouseDown = (event) => {
      if (props.disabled) return

      // 检查是否点击了拖拽手柄
      if (props.handle) {
        const handle = draggableRef.value.querySelector(props.handle)
        if (handle && !handle.contains(event.target)) {
          return
        }
      }

      event.preventDefault()
      event.stopPropagation()

      isDragging.value = true
      
      // 记录鼠标按下时的绝对位置
      startX.value = event.clientX
      startY.value = event.clientY

      // 记录元素初始位置
      initialElementX.value = elementX.value
      initialElementY.value = elementY.value

      // 计算边界
      bounds.value = calculateBounds()

      // 添加事件监听
      document.addEventListener('mousemove', handleMouseMove)
      document.addEventListener('mouseup', handleMouseUp)

      emit('drag-start', { x: elementX.value, y: elementY.value })
    }

    // 性能监控
    let frameCount = 0
    let lastFrameTime = 0
    const performanceStats = ref({
      fps: 0,
      frameTime: 0,
      isDragging: false
    })

    // 鼠标移动事件 - 使用requestAnimationFrame优化性能
    let animationFrameId = null
    
    const handleMouseMove = (event) => {
      if (!isDragging.value) return

      event.preventDefault()

      // 使用requestAnimationFrame优化动画性能
      if (animationFrameId) {
        cancelAnimationFrame(animationFrameId)
      }
      
      animationFrameId = requestAnimationFrame(() => {
        // 计算鼠标移动的总偏移量（相对于初始按下位置）
        const totalDeltaX = event.clientX - startX.value
        const totalDeltaY = event.clientY - startY.value

        // 基于元素初始位置加上总偏移量
        let newX = initialElementX.value + totalDeltaX
        let newY = initialElementY.value + totalDeltaY

        // 应用边界限制
        const constrained = constrainPosition(newX, newY)
        newX = constrained.x
        newY = constrained.y

        // 更新位置
        elementX.value = newX
        elementY.value = newY

        // 减少事件触发频率，只在位置变化时触发
        if (Math.abs(totalDeltaX) > 0.5 || Math.abs(totalDeltaY) > 0.5) {
          emit('update:x', newX)
          emit('update:y', newY)
          emit('drag-move', { x: newX, y: newY })
        }
        
        animationFrameId = null
      })
    }

    // 鼠标释放事件
    const handleMouseUp = () => {
      if (!isDragging.value) return

      isDragging.value = false

      // 清理动画帧
      if (animationFrameId) {
        cancelAnimationFrame(animationFrameId)
        animationFrameId = null
      }

      // 重置性能监控
      performanceStats.value.isDragging = false
      frameCount = 0
      lastFrameTime = 0

      // 移除事件监听
      document.removeEventListener('mousemove', handleMouseMove)
      document.removeEventListener('mouseup', handleMouseUp)

      emit('drag-end', { x: elementX.value, y: elementY.value })
    }

    // 触摸事件处理 - 直接处理触摸事件，避免模拟鼠标事件
    const handleTouchStart = (event) => {
      if (props.disabled) return

      // 检查是否点击了拖拽手柄
      if (props.handle) {
        const handle = draggableRef.value.querySelector(props.handle)
        if (handle && !handle.contains(event.target)) {
          return
        }
      }

      event.preventDefault()
      event.stopPropagation()

      const touch = event.touches[0]
      isDragging.value = true
      
      // 记录触摸按下时的绝对位置
      startX.value = touch.clientX
      startY.value = touch.clientY

      // 计算边界
      bounds.value = calculateBounds()

      // 添加触摸事件监听
      document.addEventListener('touchmove', handleTouchMove, { passive: false })
      document.addEventListener('touchend', handleTouchEnd)
      document.addEventListener('touchcancel', handleTouchEnd)

      emit('drag-start', { x: elementX.value, y: elementY.value })
    }

    // 触摸移动事件
    const handleTouchMove = (event) => {
      if (!isDragging.value) return

      event.preventDefault()

      if (animationFrameId) {
        cancelAnimationFrame(animationFrameId)
      }
      
      animationFrameId = requestAnimationFrame(() => {
        const touch = event.touches[0]
        // 计算触摸移动的总偏移量（相对于初始按下位置）
        const totalDeltaX = touch.clientX - startX.value
        const totalDeltaY = touch.clientY - startY.value

        // 基于元素初始位置加上总偏移量
        let newX = initialElementX.value + totalDeltaX
        let newY = initialElementY.value + totalDeltaY

        // 应用边界限制
        const constrained = constrainPosition(newX, newY)
        newX = constrained.x
        newY = constrained.y

        // 更新位置
        elementX.value = newX
        elementY.value = newY

        // 减少事件触发频率
        if (Math.abs(totalDeltaX) > 0.5 || Math.abs(totalDeltaY) > 0.5) {
          emit('update:x', newX)
          emit('update:y', newY)
          emit('drag-move', { x: newX, y: newY })
        }
        
        animationFrameId = null
      })
    }

    // 触摸结束事件
    const handleTouchEnd = () => {
      if (!isDragging.value) return

      isDragging.value = false

      // 清理动画帧
      if (animationFrameId) {
        cancelAnimationFrame(animationFrameId)
        animationFrameId = null
      }

      // 重置性能监控
      performanceStats.value.isDragging = false
      frameCount = 0
      lastFrameTime = 0

      // 移除触摸事件监听
      document.removeEventListener('touchmove', handleTouchMove)
      document.removeEventListener('touchend', handleTouchEnd)
      document.removeEventListener('touchcancel', handleTouchEnd)

      emit('drag-end', { x: elementX.value, y: elementY.value })
    }

    // 监听 props 变化
    const updatePosition = () => {
      elementX.value = props.x
      elementY.value = props.y
    }

    onMounted(() => {
      updatePosition()
    })

    onUnmounted(() => {
      // 清理动画帧
      if (animationFrameId) {
        cancelAnimationFrame(animationFrameId)
        animationFrameId = null
      }
      
      // 清理事件监听
      document.removeEventListener('mousemove', handleMouseMove)
      document.removeEventListener('mouseup', handleMouseUp)
      document.removeEventListener('touchmove', handleTouchMove)
      document.removeEventListener('touchend', handleTouchEnd)
      document.removeEventListener('touchcancel', handleTouchEnd)
    })

    // 暴露给父组件的方法
    const getPosition = () => ({
      x: elementX.value,
      y: elementY.value
    })
    
    const getBoundary = () => bounds.value
    
    // 获取元素尺寸的通用方法
    const getElementDimensions = () => {
      if (!draggableRef.value) return { width: 80, height: 80 }
      return {
        width: draggableRef.value.offsetWidth,
        height: draggableRef.value.offsetHeight
      }
    }
    
    const setInitialPosition = () => {
      // 计算边界
      bounds.value = calculateBounds()
      if (!bounds.value) {
        elementX.value = props.x
        elementY.value = props.y
        return
      }
      
      // 获取元素尺寸
      const { width: elementWidth, height: elementHeight } = getElementDimensions()
      
      let targetX, targetY
      
      // 根据initialPosition设置位置
      if (props.initialPosition === 'center') {
        // 居中显示：容器中心减去元素尺寸的一半
        targetX = (bounds.value.right - elementWidth) / 2
        targetY = (bounds.value.bottom - elementHeight) / 2
      } else if (props.initialPosition === 'random') {
        // 随机位置：在边界范围内随机生成，考虑元素尺寸
        targetX = Math.random() * (bounds.value.right - elementWidth)
        targetY = Math.random() * (bounds.value.bottom - elementHeight)
      } else {
        // 默认位置
        targetX = props.x
        targetY = props.y
      }
      
      // 应用安全位置计算
      const safePosition = calculateSafePosition(targetX, targetY, bounds.value)
      elementX.value = safePosition.x
      elementY.value = safePosition.y
    }
    
    // 获取容器和元素尺寸的通用方法
    const getContainerDimensions = () => {
      if (!draggableRef.value) return null
      
      const parent = draggableRef.value.parentElement
      if (!parent) return null
      
      const containerWidth = parent.clientWidth || parent.offsetWidth
      const containerHeight = parent.clientHeight || parent.offsetHeight
      const elementWidth = draggableRef.value.offsetWidth
      const elementHeight = draggableRef.value.offsetHeight
      
      // 边界检查
      if (containerWidth <= 0 || containerHeight <= 0 || elementWidth <= 0 || elementHeight <= 0) {
        console.warn('Invalid dimensions for position calculation')
        return null
      }
      
      return { containerWidth, containerHeight, elementWidth, elementHeight }
    }
    
    // 计算安全位置的通用方法
    const calculateSafePosition = (x, y, dimensions) => {
      if (!dimensions) return { x: 0, y: 0 }
      
      const { containerWidth, containerHeight, elementWidth, elementHeight } = dimensions
      
      // 确保位置在边界内
      const safeX = Math.max(0, Math.min(x, containerWidth - elementWidth))
      const safeY = Math.max(0, Math.min(y, containerHeight - elementHeight))
      
      return { x: safeX, y: safeY }
    }
    
    // 设置位置的增强方法，支持不同类型的位置设置
    const setPosition = (x, y, type = 'direct') => {
      if (type === 'direct') {
        // 直接设置位置
        bounds.value = calculateBounds()
        const constrained = constrainPosition(x, y)
        elementX.value = constrained.x
        elementY.value = constrained.y
      } else {
        // 根据类型计算位置
        const dimensions = getContainerDimensions()
        if (!dimensions) return
        
        const { containerWidth, containerHeight, elementWidth, elementHeight } = dimensions
        
        let targetX, targetY
        
        switch(type) {
          case 'center':
            // 居中位置
            targetX = (containerWidth - elementWidth) / 2
            targetY = (containerHeight - elementHeight) / 2
            break
          case 'random':
            // 随机位置
            targetX = Math.random() * (containerWidth - elementWidth)
            targetY = Math.random() * (containerHeight - elementHeight)
            break
          case 'custom':
            // 自定义位置：使用传入的固定值
            targetX = x
            targetY = y
            break
          default:
            targetX = 0
            targetY = 0
        }
        
        // 应用安全位置计算
        const safePosition = calculateSafePosition(targetX, targetY, dimensions)
        
        // 设置位置
        bounds.value = calculateBounds()
        const constrained = constrainPosition(safePosition.x, safePosition.y)
        elementX.value = constrained.x
        elementY.value = constrained.y
      }
    }
    
    // 强制重新计算边界
    const recalculateBounds = () => {
      boundsCache = null
      cacheTimestamp = 0
      bounds.value = calculateBounds()
    }

    return {
      draggableRef,
      isDragging,
      computedStyle,
      handleMouseDown,
      handleTouchStart,
      performanceStats,
      getPosition,
      getBoundary,
      setInitialPosition,
      setPosition,
      recalculateBounds
    }
  }
}
</script>

<style scoped>
.draggable {
  transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
  will-change: auto;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  transform: translateZ(0);
  -webkit-transform: translateZ(0);
  background: linear-gradient(45deg, #ff6b6b, #ee5a24);
  border-radius: 10px;
  box-shadow: 0 4px 15px rgba(0,0,0,0.2);
}

.draggable:hover {
  transform: translateZ(0) scale(1.02);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

.draggable.is-dragging {
  box-shadow: 0 8px 25px rgba(0, 0, 0, 0.2);
  transform: translateZ(0) scale(1.05);
  transition: none;
  will-change: transform;
  filter: brightness(1.1);
  z-index: 9999;
}

.draggable.is-dragging * {
  pointer-events: none;
}

/* 拖拽时的光晕效果 */
.draggable.is-dragging::before {
  content: '';
  position: absolute;
  top: -4px;
  left: -4px;
  right: -4px;
  bottom: -4px;
  background: radial-gradient(circle, rgba(0, 123, 255, 0.2) 0%, transparent 70%);
  border-radius: inherit;
  z-index: -1;
  animation: pulse 1.5s ease-in-out infinite;
}

@keyframes pulse {
  0%, 100% {
    opacity: 0.5;
    transform: scale(1);
  }
  50% {
    opacity: 0.8;
    transform: scale(1.1);
  }
}

/* 拖拽手柄样式 */
.draggable [data-drag-handle] {
  cursor: grab;
}

.draggable.is-dragging [data-drag-handle] {
  cursor: grabbing;
}

/* 响应式设计 */
@media (max-width: 768px) {
  .draggable {
    touch-action: none;
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    -khtml-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
  }
  
  .draggable.is-dragging {
    transform: translateZ(0) scale(1.08);
  }
  
  .draggable:hover {
    transform: translateZ(0) scale(1.03);
  }
}

/* 高DPI屏幕优化 */
@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) {
  .draggable {
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
  }
}
</style>
